package studio.xiaoyun.core;

import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.ConverterMatcher;
import com.thoughtworks.xstream.converters.extended.NamedCollectionConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.xstream.XStreamMarshaller;
import reactor.Environment;
import reactor.bus.EventBus;
import reactor.spring.context.config.EnableReactor;
import studio.xiaoyun.core.xstream.*;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * spring配置信息。
 */
@Configuration
@EnableReactor
public class SpringConfig {

    /**
     *
     * @return 事件驱动相关的bean
     */
    @Bean(name = "eventBus")
    public EventBus createEventBus() {
        Environment environment = new Environment();
        return EventBus.create(environment);
    }

    /**
     *
     * @return FastJson相关的配置信息
     */
    @Bean(name = "fastJsonConfig")
    public FastJsonConfig createFastJsonConfig() {
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializeConfig(getFastJsonSerializeConfig());
        return config;
    }

    /**
     *
     * @return xstream相关的配置信息
     */
    @Bean(name = "xstreamMarshaller")
    public XStreamMarshaller createXStreamMarshaller() {
        XStreamMarshaller xstreamMarshaller = new XStreamMarshaller();
        XStream xstream = xstreamMarshaller.getXStream();
        //添加自定义的转换规则
        List<ConverterMatcher> converters = new ArrayList<>();
        converters.add(new StringKeyMapConverter(xstream.getMapper()));
        converters.add(new NamedCollectionConverter(xstream.getMapper(), "array", null));
        converters.add(new NamedSingletonCollectionConverter(xstream.getMapper(),"array"));
        converters.add(new NamedArrayConverter(xstream.getMapper(),"array"));
        converters.add(new CustomDateConverter("yyyy-MM-dd HH:mm:ss"));
        converters.add(new LocalDateConverter("yyyy-MM-dd"));
        converters.add(new LocalDateTimeConverter("yyyy-MM-dd HH:mm:ss"));
        converters.add(new LocalTimeConverter("HH:mm:ss"));
        xstreamMarshaller.setConverters(converters.toArray(new ConverterMatcher[0]));
        xstreamMarshaller.setAutodetectAnnotations(true);  //自动检测注解
        return xstreamMarshaller;
    }

    /**
     * @return FastJson工具序列化时用到的配置信息
     */
    public static SerializeConfig getFastJsonSerializeConfig() {
        SerializeConfig serializeConfig = new SerializeConfig();
        serializeConfig.put(Date.class, new SimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));
        serializeConfig.put(LocalDateTime.class, (serializer, object, fieldName, fieldType, features) -> {
            if (object == null) {
                serializer.out.writeNull();
            } else {
                LocalDateTime date = (LocalDateTime) object;
                serializer.write(date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            }
        });
        serializeConfig.put(LocalDate.class, (serializer, object, fieldName, fieldType, features) -> {
            if (object == null) {
                serializer.out.writeNull();
            } else {
                LocalDate date = (LocalDate) object;
                serializer.write(date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            }
        });
        serializeConfig.put(LocalTime.class, (serializer, object, fieldName, fieldType, features) -> {
            if (object == null) {
                serializer.out.writeNull();
            } else {
                LocalTime date = (LocalTime) object;
                serializer.write(date.format(DateTimeFormatter.ofPattern("HH:mm:ss")));
            }
        });
        return serializeConfig;
    }

}
